﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace BrainTechLLC
{
    public static class AssemblyAndTypes
    {
        /// <summary>
        /// Collects all referenced assemblies that do not start with the "System" or "mscorlib" prefix and are not in the GAC
        /// </summary>
        /// <param name="assembly"></param>
        /// <returns></returns>
        public static List<Assembly> CollectAssemblies(this Assembly assembly)
        {
            List<Assembly> results = new List<Assembly>();
#if NO_SILVERLIGHT
            if (assembly == null)
                return results;

            AssemblyName[] mods = assembly.GetReferencedAssemblies();

            if (mods != null && mods.Length > 0)
            {
                for (int n = 0; n < mods.Length; n++)
                {
                    var modAssemblyName = mods[n];
                    if (modAssemblyName == null) continue;

                    string modName = modAssemblyName.Name;

                    if (modName.StartsWith("System") || modName.StartsWith("mscorlib"))
                        continue;

                    Assembly asm = Assembly.Load(modAssemblyName);

                    if (asm == null || asm.GlobalAssemblyCache) continue;

                    results.Add(asm);
                    results.AddRange(CollectAssemblies(asm));
                }
            }
#endif
            return results;
        }

        /// <summary>
        /// Crawls out from the current executing assembly and calling assembly and
        /// retrieves all discoverable assembly dependencies
        /// </summary>
        /// <returns></returns>
        public static List<Assembly> GetAllDependentAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();
#if NO_SILVERLIGHT
            assemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
            assemblies.Add(Assembly.GetEntryAssembly());
#endif
            assemblies.Add(Assembly.GetCallingAssembly());
            assemblies.Add(Assembly.GetExecutingAssembly());
            assemblies.RemoveDuplicates();

            List<Assembly> others = new List<Assembly>();

            assemblies.ForEach(assembly => others.AddRange(assembly.CollectAssemblies()));
            assemblies.AddRange(others);
            assemblies.RemoveDuplicates();

            return assemblies;
        }

        /// <summary>
        /// Returns all types from an assembly that implement/inherit from base type "T"
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a"></param>
        /// <returns></returns>
        public static List<Type> TypesThatImplement<T>(this Assembly a) where T : class
        {            
            return new List<Type>(
                from type in a.GetTypes()
                where typeof(T).IsAssignableFrom(type)
                select type);
        }
    }
}